package com.ctrip.corp.obt.shard.sql.mybatis.interceptor.dialect;

import com.ctrip.corp.obt.generic.utils.StringPool;
import com.ctrip.corp.obt.shard.constants.DbType;
import com.ctrip.corp.obt.shard.domain.dbmetainfo.DatabaseMetaInfo;
import com.ctrip.corp.obt.shard.holder.ShardSourceHolder;
import com.ctrip.corp.obt.shard.sql.mybatis.interceptor.compatibility.kingbase.KBFunctionCompatibility;
import com.ctrip.corp.obt.shard.sql.mybatis.interceptor.compatibility.kingbase.KBSemanticCompatibility;
import com.ctrip.corp.obt.shard.utils.PluginUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.SelectItem;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author x.shen
 * @desc KingBase方言类，用于实现语法兼容
 * @since 2023/11/1
 */
@Slf4j
@Component
public class KingBaseDialect implements IDialect {

    /**
     * 语义兼容
     */
    private final KBSemanticCompatibility semanticCompatibility;
    /**
     * 函数兼容
     */
    private final KBFunctionCompatibility functionCompatibility;

    public KingBaseDialect() {
        this.semanticCompatibility = new KBSemanticCompatibility();
        this.functionCompatibility = new KBFunctionCompatibility();
    }

    @Override
    public PageDialectModel buildPaginationSql(String originalSql, long offset, long limit) {
        StringBuilder sql = new StringBuilder(originalSql).append(" LIMIT ").append(FIRST_MARK);
        if (offset != 0L) {
            sql.append(StringPool.COMMA).append(SECOND_MARK);
            return new PageDialectModel(sql.toString(), offset, limit).setConsumerChain();
        } else {
            return new PageDialectModel(sql.toString(), limit).setConsumer(true);
        }
    }

    @Override
    public String buildTableSearchSql(String tableName) {
        return null;
    }

    /**
     * 前置全局处理，主要对引号等共性问题的处理
     *
     * @param sql
     * @return
     */
    @Override
    public String preHandleSql(String sql) {
        return semanticCompatibility.preHandleSql(sql);
    }

    @Override
    public void handleAsAlias(Alias alias) {
        semanticCompatibility.handleAsAlias(alias);
    }

    @Override
    public void handleColumnType(Column leftExpression, Expression rightExpression) {
        Map<DbType, DatabaseMetaInfo> xcDatabaseMetaInfoCache = ShardSourceHolder.getXcDatabaseMetaInfoCache();
        // 获取字段类型元信息
        DatabaseMetaInfo databaseMetaInfo = xcDatabaseMetaInfoCache.get(DbType.KINGBASE);
        if (Objects.isNull(databaseMetaInfo)) {
            return;
        }

        // 处理待兼容的字段类型
        semanticCompatibility.handleColumnType(leftExpression, rightExpression, databaseMetaInfo.getColumnWithTypeMap());
    }

    /**
     * 处理关键字
     *
     * @param expression
     */
    @Override
    public void handleKeyword(Expression expression) {
        semanticCompatibility.handleKeyWords(expression, KBSemanticCompatibility.SQL_KEY_WORDS);
    }

    /**
     * 函数处理
     *
     * @param expression
     */
    @Override
    public void handleFunction(Function expression) {
        functionCompatibility.handleCommonFunction(expression, KBFunctionCompatibility.SQL_COMMON_FUNCTION_MAP);
        functionCompatibility.handleSpecialFunction(expression);
    }

    @Override
    public void handleInsertPrimaryKey(Insert insert, PluginUtils.DSBoundSql boundSql) {
        semanticCompatibility.handleInsertPrimaryKey(insert, boundSql);
    }

    @Override
    public void handleOrderByWithDistinct(List<Column> needAddColumnList, List<SelectItem> selectItemsList) {
        semanticCompatibility.handleOrderByWithDistinct(needAddColumnList, selectItemsList);
    }
}
